package org.ala.distributed_redis_transaction.commons;

import org.ala.distributed_transaction_commons.AbstractDistributedTransactionFactory;
import org.ala.distributed_transaction_commons.logs.LoggerFactory;
import org.slf4j.Logger;

import redis.clients.jedis.JedisPool;


/**
 * redis分布式事务工厂
 * 
 * @author 骆毅(ala)
 * @date 2024年2月28日
 */
public abstract class AbstractRedisTransactionFactory<T extends AbstractRedisTransaction> extends AbstractDistributedTransactionFactory<T> {

	
	static Logger log = LoggerFactory.getLogger("distributed_transaction", "transaction");
	
	
	/**
	 * 
	 */
	protected JedisPool pool;
	
	
	/**
	 * 默认的最小参与者数量
	 * <p>	只会在pre_commit环节卡数量
	 */
	static final Integer DEFAULT_MIN_PARTICIPANT_COUNT = 2;
	/**
	 * 默认的事务超时时间（单位：毫秒）
	 * <p>	默认半小时
	 */
	static final Long DEFAULT_TIMEOUT = 1800000L;
	
	
	/**
	 * 开启事务
	 * <p>	指定事务管理器
	 */
	public T begin(String biz) {
		return begin(biz, DEFAULT_TIMEOUT, DEFAULT_MIN_PARTICIPANT_COUNT);
	}
	/**
	 * 开启事务
	 * <p>	指定事务管理器
	 * @
	 */
	public T begin(String biz, Integer minParticipantCount) {
		return begin(biz, DEFAULT_TIMEOUT, minParticipantCount);
	}
	/**
	 * 开启事务
	 * <p>	指定事务管理器
	 * 
	 * @param timeout	事务超时时间（单位：毫秒）
	 * @
	 */
	public T begin(String biz, Long timeout) {
		return begin(biz, timeout, DEFAULT_MIN_PARTICIPANT_COUNT);
	}
	/**
	 * 开启事务
	 * @param timeout	事务超时时间（单位：毫秒）
	 * @param minParticipantCount	最小事务参与者数量，只会在pre_commit环节卡数量（实际参与者数量>=此数值时，协调者才会往下推进事务）
	 * @
	 */
	public T begin(String biz, Long timeout, Integer minParticipantCount) {
		return begin(biz, getJedisPool(), timeout, minParticipantCount);
	}
	
	
	/**
	 * 开启事务
	 * <p>	指定事务管理器
	 * @
	 */
	public T begin(String biz, JedisPool pool) {
		return begin(biz, pool, DEFAULT_TIMEOUT, DEFAULT_MIN_PARTICIPANT_COUNT);
	}
	/**
	 * 开启事务
	 * <p>	指定事务管理器
	 * @
	 */
	public T begin(String biz, JedisPool pool, Integer minParticipantCount) {
		return begin(biz, pool, DEFAULT_TIMEOUT, minParticipantCount);
	}
	/**
	 * 开启事务
	 * <p>	指定事务管理器
	 * 
	 * @param timeout	事务超时时间（单位：毫秒）
	 * @
	 */
	public T begin(String biz, JedisPool pool, Long timeout) {
		return begin(biz, pool, timeout, DEFAULT_MIN_PARTICIPANT_COUNT);
	}
	/**
	 * 开启事务
	 * <p>	指定事务管理器
	 * @param txManager 本地事务管理器
	 * @param timeout	事务超时时间（单位：毫秒）
	 * @param minParticipantCount	最小事务参与者数量，只会在pre_commit环节卡数量（实际参与者数量>=此数值时，协调者才会往下推进事务）
	 * @
	 */
	public T begin(String biz, JedisPool pool, Long timeout, Integer minParticipantCount) {
		T tx = build(biz, timeout, 1, 1, minParticipantCount, 1);
		tx.setPool(pool);
		tx.setBiz(biz);
		tx.begin();
		return tx;
	}
	
	
	/**
	 * 取事务管理器
	 */
	protected JedisPool getJedisPool() {
		try {
			return applicationContext.getBean(JedisPool.class);
		} catch (Exception e) {
			String[] beanNames = applicationContext.getBeanNamesForType(JedisPool.class);
			if (beanNames == null || beanNames.length == 0) {
				log.warn("[" + this.getClass().getSimpleName() + " getJedisPool] 当前环境中找不到bean class:JedisPool");
				throw e;
			} else {
				log.warn("[" + this.getClass().getSimpleName() + " getJedisPool] 当前环境中存在多个bean class:JedisPool，无法确认要使用哪一个。请在开启事务时使用begin(JedisPool,...)方法 beanNames:" + String.join(",", beanNames));
				return null;
			}
		}
	}

}
